﻿/*! ************************************************************
 * \file
 * \brief 单例进程，限制同一个程序只能启动一次
 *
 * \authors 林胜勇
 *
 * \date
 * \verbatim
 * 变更记录：
 * 2023-11-30，林胜勇:
 *   创建文件
 * \endverbatim
 ****************************************************************/
#pragma once

#include <string>

/// 单例进程检查
class SingletonApp {
public:
    /// 构造器
    ///  \param appName 程序名称，不同程序需要设置不同值
    /// \param autoExit 当程序已运行了一份，本次启动是否立即退出即调用exit
    SingletonApp(const std::string &appName, bool autoExit = false);

    ~SingletonApp();

    /// 序是否已经运行和存在
    bool isRunning() const;

    /// 杀掉第1个获取lock并在运行的程序，并获取lock
    /// \param wait 是否阻塞等待获取lock，0是不等待，大于0是最长等待时间，单位毫秒
    /// \return 是否已经杀掉第1个进程并获取lock
    bool tryKillAndLock(int waitTime = 0);

    /// 获取应用名称
    std::string appName() const;

private:
    /// 尝试锁定lock文件，并返回是否lock成功，即是第1次启动
    bool tryLock();

    /// 读取lock文件中的进程ID，用来将其杀掉
    unsigned long long readProcessID();

    /// 将进程ID写入lock文件
    bool writeProcessID();

private:
    /// 序是否启动过，即本次是否非首次运行
    bool m_appIsRunning;

    /// 打开锁文件的句柄
    int m_singleFileLockFD;

    /// 应用程序名称
    std::string m_appName;

    /// 检测程序存在时，是否自动退出
    bool m_autoExit;

    /// 应用程序完整路径
    std::string m_appPath;

    /// 获取lock的正在运行的进程ID
    unsigned long long m_runningAppID{0};
};